(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Fenzhi = {}));
})(this, (function (exports) { 'use strict';

  /*
   * 转换时间
   * CustomDateFtt(1565059668200,"yyyy-MM-dd hh:mm:ss") => '2019-08-06 10:47:48'
   * CustomDateFtt(1565059668200,"yyyy-MM-dd") => '2019-08-06'
   */
  function CustomDateFtt(date, fmt) {
    if (date != null && date != '' && date != undefined) {
      if (typeof date == 'string') {
        date = date.replace(/-/g, '/');
      }
      var date = new Date(date);
      var o = {
        'M+': date.getMonth() + 1,
        'd+': date.getDate(),
        'h+': date.getHours(),
        'm+': date.getMinutes(),
        's+': date.getSeconds(),
        'q+': Math.floor((date.getMonth() + 3) / 3), //季度
        S: date.getMilliseconds(), //毫秒
      };
      o.S < 100 && (o.S = o.S < 10 ? '00' + o.S : '0' + o.S);
      if (/(y+)/.test(fmt))
        fmt = fmt.replace(
          RegExp.$1,
          (date.getFullYear() + '').substr(4 - RegExp.$1.length)
        );
      for (var k in o)
        if (new RegExp('(' + k + ')').test(fmt))
          fmt = fmt.replace(
            RegExp.$1,
            RegExp.$1.length == 1
              ? o[k]
              : ('00' + o[k]).substr(('' + o[k]).length)
          );
    } else {
      fmt = '';
    }
    return fmt;
  }

  // numberFormat (千分位)分隔符
  function numberFormat(num) {
    if (isNaN(parseFloat(num)) || parseFloat(num) === Infinity) return '';
    let fixedIndex =
      num.toString().indexOf('.') === -1
        ? 0
        : num.toString().split('.')[1].length;
    return parseFloat(num)
      .toFixed(fixedIndex)
      .replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,');
  }

  // NumberToFixed 四舍五入
  // 注：js自带的toFixed有银行家算法缺陷，故重写 例：toFixed(1.255, 2)
  function NumberToFixed(num, digits = 0) {
    if (isNaN(parseFloat(num)) || parseFloat(num) === Infinity) return '';
    let zeroStrNum = num.toString();

    // 处理科学计算情况
    if (zeroStrNum.includes('e')) {
      const m = zeroStrNum.match(/\d(?:\.(\d*))?e([+-]\d+)/);
      zeroStrNum = num.toFixed(Math.max(0, (m[1] || '').length - m[2]));
    }

    let isNegativeNum = false;
    // 判断是否为负数
    if (zeroStrNum.startsWith('-')) {
      isNegativeNum = true;
      zeroStrNum = zeroStrNum.slice(1);
    }
    // 获取小数点位置
    const dotIndex = zeroStrNum.indexOf('.');
    // 如果是整数/保留小数位数等于超过当前小数长度，则直接用toFixed返回
    if (dotIndex === -1 || zeroStrNum.length - (dotIndex + 1) <= digits) {
      return num.toFixed(digits);
    }

    // 找到需要进行四舍五入的部分
    let numArr = zeroStrNum.match(/\d/g) || [];
    numArr = numArr.slice(0, dotIndex + digits + 1);

    // 核心处理逻辑
    if (parseInt(numArr[numArr.length - 1], 10) > 4) {
      // 如果最后一位大于4，则往前遍历+1
      for (let i = numArr.length - 2; i >= 0; i--) {
        numArr[i] = String(parseInt(numArr[i], 10) + 1);
        // 判断这位数字 +1 后会不会是 10
        if (numArr[i] === '10') {
          // 10的话处理一下变成 0，再次for循环，相当于给前面一个 +1
          numArr[i] = '0';
        } else {
          // 小于10的话，就打断循环，进位成功
          break;
        }
      }
    }
    // 将小数点加入数据
    numArr.splice(dotIndex, 0, '.');

    // 处理多余位数
    numArr.pop();

    // 如果事负数，添加负号
    if (isNegativeNum) {
      numArr.unshift('-');
    }

    return Number(numArr.join('')).toFixed(digits);
  }

  /**
   * 验证码校验
   * @param {*} val
   * @returns
   */
  function passwordVerifiersFn(val) {
    let valArr = val.split('');
    let illegalStr = []; // 非法字符有哪些
    let verification1 = `ABCDEFGHIJKLMNOPQRSTUVWXYZ`;
    let verification2 = `abcdefghijklmnopqrstuvwxyz`;
    let verification3 = `0123456789`;
    let verification4 = `!@#$&*.`;
    let verificatType1 = []; // 大写字母收集
    let verificatType2 = []; // 小写字母收集
    let verificatType3 = []; // 数字类型收集
    let verificatType4 = []; // 特殊字母收集
    let verificationStr = verification1
      .concat(verification2)
      .concat(verification3)
      .concat(verification4);
    valArr.forEach((item) => {
      if (verificationStr.includes(item)) {
        if (verification1.includes(item)) {
          verificatType1.push(item);
        } else if (verification2.includes(item)) {
          verificatType2.push(item);
        } else if (verification3.includes(item)) {
          verificatType3.push(item);
        } else if (verification4.includes(item)) {
          verificatType4.push(item);
        }
      } else {
        illegalStr.push(item);
      }
    });

    let signArr = [];
    valArr.length < 8 && signArr.push('密码长度小于8位');
    valArr.length > 12 && signArr.push('密码长度大于12位');
    !verificatType1.length && signArr.push('未包含大写字母');
    !verificatType2.length && signArr.push('未包含小写字母');
    !verificatType3.length && signArr.push('未包含数字');
    !verificatType4.length && signArr.push('未包含特殊符号');
    illegalStr.length && signArr.push(`包含未指定字符：${signArr.join('')}`);

    if (signArr.length) {
      signArr.unshift('密码校验存在以下问题：');
      signArr.push('');
      signArr.push('温馨提示：');
      signArr.push('密码规则：8-12位，包含大小写字母、数字、特殊符号');
      signArr.push(`大写字母取值范围：${verification1}`);
      signArr.push(`小写字母取值范围：${verification2}`);
      signArr.push(`数字取值范围：${verification3}`);
      signArr.push(`特殊符号取值范围：${verification4}`);
      return signArr.join('\n');
    } else {
      return true;
    }
  }

  /* 设计到字符串隐藏类的函数 */

  // 转换姓名
  function HideStrPersonName(nameStr = '', character = '*') {
    try {
      if (CustomGetTypeOf(nameStr) !== 'string') {
        throw new Error('传入的姓名为非字符串');
      }

      if ([0, 1].includes(nameStr.length)) {
        return nameStr;
      } else if ([2].includes(nameStr.length)) {
        return nameStr.charAt(0) + character;
      } else {
        // 保留前一后一
        return nameStr.split('').reduce((prev, item, index) => {
          return (prev += [0, nameStr.length - 1].includes(index)
            ? item
            : character);
        }, '');
      }
    } catch (err) {
      console.log(err);
    }
  }

  // 转换地址:从城市后面都显示成X，只显示省市即可
  function HideStrAddress(idNumber = '', type = 1) {}

  /**
   * 判断一个数组是否是正序的二维数组
   * @param {*} arr
   * @returns {boolean}
   */
  function IsAscendingOrderArr(arr = []) {
    if (!arr.length) return false;
    let flag = true;
    arr.forEach((item) => {
      let flag_01 = CustomGetTypeOf(item[0]) === 'number';
      let flag_02 = CustomGetTypeOf(item[1]) === 'number';
      let flag_03 = Number.isInteger(item[0]) && item[0] > -1;
      let flag_04 = Number.isInteger(item[1]) && item[1] > -1;
      let flag_05 = item[0] <= item[1];
      if (!(flag_01 && flag_02 && flag_03 && flag_04 && flag_05)) {
        flag = false;
      }
    });
    return flag;
  }
  /**
   * 判断是否一维数字数组
   * @param {array} arr
   * @returns {boolean}
   */
  function OnedimensionalNumberArray(arr = []) {
    if (!arr.length) return false;
    let flag = true;
    arr.forEach((item) => {
      let flag_01 = CustomGetTypeOf(item) === 'number';
      let flag_02 = Number.isInteger(item); // 判断是否是整数
      let flag_03 = item > -1;
      if (!(flag_01 && flag_02 && flag_03)) {
        flag = false;
      }
    });
    return flag;
  }

  /**
   * 字符串处理的通用函数
   * @param {string} processStr -- 传入的字符串
   * @param {number,array} param_1
   * @param {nunber,string} param_2
   * @param {nunber} param_3
   * @returns {string}
   * 示例一：HideStrGeneral('abcdefghijklmn',[0,1,4,5,6],'x');// 动态替换索引位置的字符
   * 示例二：HideStrGeneral('abcdefghijklmn',1,5,'x');// 替换连续位置的字符
   * 示例三：HideStrGeneral('abcdefghijklmn',[[0,2],[4,6]],'x');// 替换分段索引位置的字符
   */
  function HideStrGeneral(
    processStr = '',
    param_1, //[3,5]    [[1,3],[3,5],[6,8]]
    param_2 = '*',
    param_3 = '*'
  ) {
    try {
      if (CustomGetTypeOf(processStr) !== 'string') {
        throw new Error('请传入字符串');
      }
      if (!processStr.length) {
        return processStr;
      }

      if (CustomGetTypeOf(param_1) === 'array') {
        if (OnedimensionalNumberArray(param_1)) {
          // 纯一维数字数组
          return processStr.split('').reduce((prev, item, index) => {
            return (prev += param_1.includes(index) ? param_2 : item);
          }, '');
        } else if (IsAscendingOrderArr(param_1)) {
          // 纯二维数字数组
          param_1.forEach((item_01) => {
            processStr = processStr.split('').reduce((prev, item_02, index) => {
              return (prev +=
                item_01[0] <= index && index <= item_01[1] ? param_2 : item_02);
            }, '');
          });
          return processStr;
        } else {
          throw new Error('请检查数组格式');
        }
      } else if (CustomGetTypeOf(param_1) === 'number') {
        let flag_01 = Number.isInteger(param_1); // 判断是否是整数
        let flag_02 = Number.isInteger(param_2); // 判断是否是整数
        if (CustomGetTypeOf(param_2) === 'number' && flag_01 && flag_02) {
          if (param_1 > param_2) {
            throw new Error('字符串截取开始位置不能大于结束位置');
          }
          param_1 = param_1 > 0 ? param_1 : 0;
          param_2 = param_2 > processStr.length ? processStr.length : param_2;
          return processStr.split('').reduce((prev, item, index) => {
            return (prev +=
              param_1 <= index && index <= param_2 ? param_3 : item);
          }, '');
        } else {
          throw new Error('第二个参数、第三个参数需为非负整数');
        }
      } else {
        return processStr;
      }
    } catch (err) {
      console.log(err);
    }
  }

  /**
   * 获取类型(以全小写返回)
   * 2023年3月16日10:48:46
   * @param {*} obj
   * @returns
   * @since 1.0.17 郭坤 2023年3月16日10:51:25
   */
  function CustomGetTypeOf(obj) {
    if (Number.isNaN(obj) && isNaN(obj)) return 'nan';
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
  }

  /**
   * 函数防抖：fn函数在最后一次调用时刻的delay毫秒之后执行！
   * @param fn 执行函数
   * @param delay 时间间隔
   * @param isImmediate 为true，debounce会在delay时间间隔的开始时立即调用这个函数
   * @returns {Function}
   * @since 1.0.17 郭坤 2023年3月16日11:18:21
   */
  function CustomDebounce(fn, delay = 100, isImmediate = false) {
    var timer = null; // 初始化timer，作为计时清除依据
    return function () {
      var context = this; // 获取函数所在作用域this
      var args = arguments; // 取得传入参数
      clearTimeout(timer);
      if (isImmediate && timer === null) {
        fn.apply(context, args); // 时间间隔外立即执行
        timer = 0;
        return;
      }
      timer = setTimeout(function () {
        fn.apply(context, args);
        timer = null;
      }, delay);
    };
  }

  /**
   * 验证码校验
   * @param {*} val
   * @returns true/false
   */
  const CustomPasswordVerifiersFn = (val) => passwordVerifiersFn(val);

  /**
   * 姓名处理
   * @param {*} str
   * @param {*} type
   * @returns
   */
  const CustomPersonNameFn = (str, params) =>
    HideStrPersonName(str, params);

  const CustomHideStrGeneral = (...params) => HideStrGeneral(...params);
  // export const CustomHideStrGeneral = (processStr, param_1, param_2, param_3) =>
  //   HideStrGeneral(processStr, param_1, param_2, param_3);

  exports.CustomDateFtt = CustomDateFtt;
  exports.CustomDebounce = CustomDebounce;
  exports.CustomGetTypeOf = CustomGetTypeOf;
  exports.CustomHideStrGeneral = CustomHideStrGeneral;
  exports.CustomPasswordVerifiersFn = CustomPasswordVerifiersFn;
  exports.CustomPersonNameFn = CustomPersonNameFn;
  exports.HideStrAddress = HideStrAddress;
  exports.HideStrGeneral = HideStrGeneral;
  exports.HideStrPersonName = HideStrPersonName;
  exports.NumberToFixed = NumberToFixed;
  exports.numberFormat = numberFormat;
  exports.passwordVerifiersFn = passwordVerifiersFn;

}));
